#ifndef __NET_SOCKET__
#define __NET_SOCKET__

#include<iostream>
#include<string>

#include<errno.h>
#include<unistd.h>
#include<signal.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#include"../log/log.hpp"

#define MAX_LISTEN 1024

//忽略SIGPIPE信号，避免服务器由于给客户端断开连接进行send触发异常，导致程序崩溃
class NetWork
{
public:
    NetWork()
    {
        DBG("SIGPIPE ignore\n");
        DBG("SIGHUP ignore\n");
        signal(SIGPIPE,SIG_IGN);
        signal(SIGHUP,SIG_IGN);
    }
};

static NetWork nw;

class Socket
{
public:
    Socket()
        :_socket_fd(-1)
    {

    }

    Socket(int fd)
        :_socket_fd(fd)
    {

    }

    //获得socket的fd
    int get_fd(){return _socket_fd;}

    //创建socket
    bool Create()
    {
        _socket_fd=socket(AF_INET,SOCK_STREAM,0);
        if(_socket_fd<0)
        {
            ERR("create socket failed!");
            return false;
        }
        return true;
    }

    //绑定ip端口
    bool Bind(const std::string& ip,uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        addr.sin_port=htons(port);
        int ret=bind(_socket_fd,(struct sockaddr*)&addr,sizeof(addr));
        if(ret<0)
        {
            ERR("bind address failed!");
            return false;
        }
        return true;
    }

    //将socketfd设置监听
    bool Listen(int backlog=MAX_LISTEN)
    {
        int ret=listen(_socket_fd,backlog);
        if(ret<0)
        {
            ERR("socket listen failed!");
            return false;
        }
        return true;
    }

    //获取新连接
    int Accept()
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        int newfd=accept(_socket_fd,(struct sockaddr*)&peer,&len);
        if(newfd<0)
        {
            ERR("socket accept failed!");
            return -1;
        }
        _socket_port=ntohs(peer.sin_port);
        inet_ntop(AF_INET, &(peer.sin_addr), _socket_addr, INET_ADDRSTRLEN);
        return newfd;
    }

    //向服务器发起连接
    bool Connect(const std::string& ip,uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        addr.sin_port=htons(port);
        int ret=connect(_socket_fd,(struct sockaddr*)&addr,sizeof(addr));
        if(ret<0)
        {
            ERR("connect server failed!");
            return false;
        }
        return true;

    }

    //接收数据
    ssize_t Recv(void* buf,size_t len,int flag=0)
    {
        ssize_t ret=recv(_socket_fd,buf,len,flag);
        if(ret<0)
        {
            //EINTR：当前socket的阻塞等待被信号打断了
            //EAGAIN：socket的接收缓冲区中没有数据,在非阻塞的情况下才有这个错误
            //没有接收到数据
            if(errno==EINTR||errno==EAGAIN)return 0;
            ERR("socket recv failed!");
            return -1;
        }
        return ret;
    }

    //非阻塞接收
    ssize_t NonBlockRecv(void* buf,size_t len)
    {
        return Recv(buf,len,MSG_DONTWAIT);
    }

    //发送数据
    ssize_t Send(const void* buf,size_t len,int flag=0)
    {
        ssize_t ret=send(_socket_fd,buf,len,flag);
        if(ret<0)
        {
            if(errno==EINTR||errno==EAGAIN)return 0;
            ERR("socket send failed!");
            return -1;
        }
        return ret;
    }

    //非阻塞发送
    ssize_t NonBlockSend(void* buf,size_t len)
    {
        return Send(buf,len,MSG_DONTWAIT);
    }

    //开启地址端口复用
    void ReuseAddress()
    {
        int val=1;
        setsockopt(_socket_fd,SOL_SOCKET,SO_REUSEADDR,(void*)&val,sizeof(int));
        val=1;
        setsockopt(_socket_fd,SOL_SOCKET,SO_REUSEPORT,(void*)&val,sizeof(int));
    }

    //设置socket为非阻塞
    void NonBlock()
    {
        int flag=fcntl(_socket_fd,F_GETFL,0);
        fcntl(_socket_fd,F_SETFL,flag|O_NONBLOCK);
    }

    //创建服务器连接
    bool create_server(const std::string& ip,uint16_t port,bool block_flag=false)
    {
        if(Create()==false)return false;
        if(block_flag)NonBlock();
        if(Bind(ip,port)==false)return false;
        if(Listen()==false)return false;

        ReuseAddress();
        return true;
    }

    //创建客户端连接
    bool create_client(const std::string& ip,uint16_t port)
    {
        if(Create()==false)return false;
        if(Connect(ip,port)==false)return false;

        return true;
    }

    //关闭套接字
    void Close()
    {
        if(_socket_fd!=-1)
        {
            close(_socket_fd);
            _socket_fd=-1;
        }
    }

    ~Socket()
    {
        Close();
    }

    int _socket_port;
    char* _socket_addr;

private:
    int _socket_fd;

};

#endif